<!--
 * @Author: aster lipian1004@163.com
 * @Date: 2025-02-20 17:08:32
 * @FilePath: \aster-flowable-uniapp\src\components\form\render\associated-form.vue
 * @Description: 关联表单
 * Copyright (c) 2025 by Aster, All Rights Reserved.
-->
<template>
  <van-field
    v-if="!_hidden"
    :model-value="_value?.label"
    :name="formItemProp"
    :placeholder="_placeholder"
    :readonly="true"
    :required="_required"
    :rules="_rules"
    :input-align="FieldInputAlignEnum.RIGHT"
    :error-message-align="FieldInputAlignEnum.RIGHT"
    :label-width="showLabel ? '' : '5rpx'"
    is-link
    @click="handleOpen"
  >
    <template #label>
      <text v-if="showLabel">{{ formItem.title }}</text>
    </template>
  </van-field>

  <van-popup v-model:show="showPicker" round position="bottom" class="popup-content">
    <view class="flex justify-center text-lg font-bold py-30rpx">请选择</view>
    <van-checkbox-group v-if="!_readonly" v-model="selectedValues">
      <van-cell-group inset v-if="popoverOptions && popoverOptions.length > 0">
        <van-cell
          v-for="(item, index) in popoverOptions"
          :key="index"
          clickable
          size="large"
          :title="item.label"
          @click="clickItem(item, index)"
        >
          <template #right-icon>
            <van-checkbox
              :name="item.value"
              :ref="(el) => (checkboxRefs[index] = el)"
              @click.stop="clickItem(item, index)"
            />
          </template>
        </van-cell>
      </van-cell-group>
    </van-checkbox-group>
  </van-popup>
</template>
<script setup lang="ts">
  import { evaluateFormula } from '@/utils/workflow';
  import { computed, PropType, ref, watch } from 'vue';
  import { isNotEmpty } from '@/utils/is';
  import { FormPermissionEnum } from '@/enums/workFlowEnum';
  import { FieldInputAlignEnum } from '@/enums/formEnum';
  import { instanceListByCodeApi } from '@/api/workflow/process';

  const emit = defineEmits(['update:value']);
  const props = defineProps({
    value: {
      type: Object as PropType<WorkComponent.TreeNode>,
      default: () => {
        return { label: '', value: '' };
      },
    },
    mode: {
      type: String as PropType<'design' | 'form' | 'search' | 'table' | 'print'>,
      default: 'design',
    },
    formData: {
      type: Object as PropType<WorkForm.FormDataModel>,
      default: {},
    },
    formItem: {
      type: Object as PropType<WorkComponent.ComponentConfig>,
      default: {},
    },
    tableId: {
      type: String,
      default: '',
    },
    tableIndex: {
      type: Number,
      default: 0,
    },
    showLabel: {
      type: Boolean,
      default: true,
    },
  });

  // 显示弹出层
  const showPicker = ref(false);
  // 关联表单的流程实例
  const associatedList = ref<Process.InstanceInfo[]>([]);
  // 关联表单的流程实例选项
  const associatedOptions = ref<{ label: string; value: string }[]>([]);
  // 弹窗选项
  const popoverOptions = ref<{ label: string; value: string }[]>([]);
  // 已选择的值
  const selectedValues = ref<string[]>([]);
  // 注册组件
  const checkboxRefs = ref<any[]>([]);

  // 打开弹出层
  const handleOpen = () => {
    if (!_readonly.value) {
      showPicker.value = true;
    }
  };

  /**
   * @description: 确认选择
   */
  const clickItem = (obj: { label: string; value: string }, index: number) => {
    checkboxRefs.value[index].toggle();
    if (selectedValues.value.length > 0) {
      selectedValues.value = [obj.value];
      handleChange(obj.value);
      _value.value = obj;
    } else {
      _value.value = { label: '', value: '' };
    }
    showPicker.value = false;
  };

  /**
   * @description: 处理关联表单变化
   * @param {*} procInstId 选中的值
   * @return {*}
   */
  const handleChange = (procInstId: string) => {
    const associatedFormData = associatedList.value.find(
      (item) => procInstId && item.procInstId === procInstId,
    );
    if (
      associatedFormData &&
      props.formItem.props.dataFill &&
      props.formItem.props.dataFill.length > 0
    ) {
      // 先处理没有明细表的规则
      const rules = props.formItem.props.dataFill.filter((item: WorkComponent.DataFillModel) => {
        return item.currentFieldId.indexOf('.') == -1;
      });
      if (isNotEmpty(rules)) {
        rules.forEach((rule: WorkComponent.DataFillModel) => {
          const fieldValue = associatedFormData[rule.associatedFieldId];
          props.formData[rule.currentFieldId] = fieldValue;
        });
      }
      // 再处理有明细表的规则
      const tableRules = props.formItem.props.dataFill.filter(
        (item: WorkComponent.DataFillModel) => {
          return item.currentFieldId.indexOf('.') != -1;
        },
      );
      if (isNotEmpty(tableRules)) {
        tableRules.forEach((rule: WorkComponent.DataFillModel) => {
          const arr = rule.currentFieldId.split('.');
          const tableId = arr[0];
          const tableFieldId = arr[1];

          let obj = {};
          obj[tableFieldId] = associatedFormData[rule.associatedFieldId];
          props.formData[tableId] = [obj];
        });
      }
    }
  };

  /**
   * @description: 提示词
   */
  const _placeholder = computed(() => {
    if (_readonly.value) {
      return '';
    }
    return _value.value && _value.value.value && isNotEmpty(_value.value.value) ? '' : '请选择';
  });

  // 键
  const formItemProp = computed(() => {
    if (isNotEmpty(props.tableId)) {
      return props.tableId + '.' + props.tableIndex + '.' + props.formItem.id;
    } else {
      return props.formItem.id;
    }
  });

  /**
   * @description: 是否必填, true-必填
   */
  const _required = computed(() => {
    return props.formItem.props.required;
  });

  /**
   * @description: 是否只读, true-只读
   */
  const _readonly = computed(() => {
    let r = props.formItem.props.readonly;
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.READONLY;
    }
    return r;
  });

  /**
   * @description: 校验规则
   */
  const _rules = computed(() => {
    const isRequired = _required.value;
    if (props.mode != 'form') {
      return [];
    }
    return isRequired ? [{ required: true, message: `请输入${props.formItem.title}` }] : [];
  });

  /**
   * @description: 组件值
   */
  const _value = computed({
    get() {
      return props.value;
    },
    set(val) {
      emit('update:value', val);
    },
  }) as any;

  /**
   * @description: 是否隐藏, true-隐藏
   */
  const _hidden = computed(() => {
    let r = false;
    // 解析隐藏条件公式
    if (props.formItem.props.hidden) {
      let expression = props.formItem.props.hidden;
      // 如果是子表中的控件，则需要用到下标
      if (isNotEmpty(props.tableId)) {
        expression = expression.replaceAll('?', props.tableIndex);
      }
      r = evaluateFormula(expression, props.formData);
    }
    // 判断流程节点下该控件是否隐藏
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.HIDDEN;
    }
    return r;
  });

  /**
   * @description: 监听表单数据变化
   */
  const _formData = computed(() => {
    return JSON.parse(JSON.stringify(props.formData));
  });

  /**
   * @description: 监听关联表单配置，获取表单选项
   */
  watch(
    () => props.formItem.props.formCode,
    async (val: string[]) => {
      if (isNotEmpty(val)) {
        await instanceListByCodeApi(val[1], '9').then(({ data }) => {
          if (data && data.length > 0) {
            associatedList.value = data;
            associatedOptions.value = data
              .filter((item: Process.InstanceInfo) => {
                if (isNotEmpty(props.formItem.props.dataScope.value)) {
                  return evaluateFormula(props.formItem.props.dataScope.value, item);
                } else {
                  return true;
                }
              })
              .map((item: Process.InstanceInfo) => {
                const labels: string[] = props.formItem.props.displayField.map(
                  (fieldId: string) => {
                    return item[fieldId];
                  },
                );
                return {
                  value: item.procInstId ? item.procInstId : '',
                  label: labels.join('-'),
                };
              });
          } else {
            associatedOptions.value = [];
          }
          popoverOptions.value = JSON.parse(JSON.stringify(associatedOptions.value));
        });
      }
    },
    { immediate: true, deep: true },
  );

  /**
   * @description: 监听表单数据变化，动态更新选项
   */
  watch(
    () => _formData.value,
    async (nval, oval) => {
      if (
        nval &&
        props.formItem &&
        props.formItem.props.dataScope &&
        isNotEmpty(props.formItem.props.dataScope.value)
      ) {
        // 数据范围限定公式
        const dataScopeFormula = props.formItem.props.dataScope.value;
        Object.keys(nval).forEach((key) => {
          if (dataScopeFormula.indexOf(key) != -1 && oval != undefined && nval[key] != oval[key]) {
            associatedOptions.value = associatedList.value
              .filter((item: Process.InstanceInfo) => {
                return evaluateFormula(dataScopeFormula, { ...item, ...nval });
              })
              .map((item: Process.InstanceInfo) => {
                const labels: string[] = props.formItem.props.displayField.map(
                  (fieldId: string) => {
                    return item[fieldId];
                  },
                );
                return {
                  value: item.procInstId ? item.procInstId : '',
                  label: labels.join('-'),
                };
              });
            popoverOptions.value = JSON.parse(JSON.stringify(associatedOptions.value));
          }
        });
      }
    },
    { immediate: true, deep: true },
  );

  defineExpose({
    _hidden,
  });
</script>
<style scoped lang="scss">
  .popup-content {
    max-height: 60%;
    min-height: 40%;
  }
</style>
